package com.pan.vo.utils;


import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Component
public class ConvertObject {

    public static Object entityToVo(Class voClass,Object entity){
        Object vo ;
        try {
            vo = voClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        Class entityClass = entity.getClass();
        Field[] fields = voClass.getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            String memberName = field.getName();
            Class memberType = field.getType();
            String firstUp = memberName.substring(0,1).toUpperCase()+memberName.substring(1);
            String voSetterName = "set"+firstUp;
            String entityGetterName = "get"+firstUp;
            try {
                Method voSetter = voClass.getMethod(voSetterName,memberType);
                Method entityGetter = entityClass.getMethod(entityGetterName);
                Object value = entityGetter.invoke(entity);
                voSetter.invoke(vo,value);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        });
        return vo;
    }

    public static Object forceConvertObject(Class newClass,Object oldObject) {
        Object newObject;
        try {
            newObject = newClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        Field[] newObjectFields = newClass.getDeclaredFields();
        Field[] oldObjectFields = oldObject.getClass().getDeclaredFields();
        Map<String, Field> oldMap = new HashMap<>();
        Arrays.stream(oldObjectFields).forEach(field -> oldMap.put(field.getName(), field));
        Arrays.stream(newObjectFields).forEach(field -> {
            String memberName = field.getName();
            Field oldField = oldMap.get(memberName);
            if (oldField!=null){
                Object value;
                oldField.setAccessible(true);
                try {
                    value = oldField.get(oldObject);
                    field.setAccessible(true);
                    field.set(newObject,value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });



        return newObject;
    }


    public static Object convertObject(Class newClass,Object oldObject){
        Object newObject;
        try {
            newObject = newClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        Field[] newObjectFields = newClass.getDeclaredFields();
        Field[] oldObjectFields = oldObject.getClass().getDeclaredFields();
        Map<String,Class> newMap = new HashMap<>();
        Map<String,Class> oldMap = new HashMap<>();
        Arrays.stream(newObjectFields).forEach(field -> newMap.put(field.getName(),field.getType()));
        Arrays.stream(oldObjectFields).forEach(field -> oldMap.put(field.getName(),field.getType()));
        Class oldClass = oldObject.getClass();
        newMap.forEach((memberName,memberType) -> {
            Class oldMemberType = oldMap.get(memberName);
            if (oldMemberType!=null&&oldMemberType==memberType) {
                String firstUp = memberName.substring(0,1).toUpperCase()+memberName.substring(1);
                String getterName = "get"+firstUp;
                String setterName = "set"+firstUp;
                try {
                    Method oldClassGetter = oldClass.getMethod(getterName);
                    Method newClassSetter = newClass.getMethod(setterName,memberType);
                    Object value = oldClassGetter.invoke(oldObject);
                    newClassSetter.invoke(newObject,value);
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        return newObject;
    }
}
